#ifndef SERVER_H
#define SERVER_H


#include <QStringList>
#include <QTcpServer>
#include <QUdpSocket>
#include <QThread>
#include "SimpleCrypt.h"
#include "Card.h"
#include "ClientThread.h"

class GameMaster;


class Server : public QTcpServer
{
    Q_OBJECT

public:
    /*!
     * \brief The server's constructor.
     * \param _gm is a GameMaster object which allows the server to send messages back.
     */
    Server(QObject *parent = 0);

    /*!
     * \brief Wrties a message to every client connected to the server.
     * \param _msg is a QString which contains the message to be sent to every client.
     */
    void writeToClients(const QString &_msg);

    /*!
     * \brief Sends a request to the relevant client asking for their bid.
     * \param client is a QString which represents the name of the client to send the request to.
     */
    QStringList getBid( int, QString client);

    /*!
     * \brief Sends a message to the relevant client indicating that a bid has been made.
     * \param client is a QString which represents the name of the client to send the message to.
     * \param client_name is a QString which represents the name of the client who made the bid.
     * \param act is a QString which represents the bidding action.
     * \param count is an int which represents the card's value.
     * \param suit is a QString indicating which suit the bidder selected.
     */
    bool sendBid( int, QString cname, QString client_name, QString act, QString count, QString suit);

    /*!
     * \brief Sends a request to the relevant client asking for their move.
     * \param client_name is a QString which represents the name of the client to send the request to.
     */
    QStringList getMove( int, QString client_name);

    /*!
     * \brief Sends a request to the relevant dummy client asking for their move.
     * \param client_name is a QString which represents the name of the client to send the request to.
     */
    QStringList getDummyMove( int, QString name);

    /*!
     * \brief Sends a message to the relevant client indicating that a move has been made.
     * \param client_name is a QString which represents the name of the client to send the request to.
     * \param client_dir is an integer representation of the direction of the client (NSEW).
     * \param suit is a QString which represents the card's suit.
     * \param value is a QString which represents the card's value.
     */
    bool sendMove( QString client_name, int client_dir, QString suit, QString value);

    /*!
     * \brief Sends an acknowledge message to the relevant client.
     * \param client_name is a QString which represents the name of the client to send the ack to.
     * \param success is an int which indidates whether the request was successful.
     * \param error_code is an int which indicates which error has occured.
     */
    void sendAcknowledge( int, QString client_name, int success, int error_code);

    /*!
     * \brief Sends a phase message to the relevant client.
     * \param client_name is a QString which represents the name of the client to send the message to.
     * \param phase is a QString indicating which phase to send.
     */
    bool sendPhase( int, QString user_name, QString phase);

    /*!
     * \brief Sends a contract message to the relevant client.
     * \param client_name is a QString which represents the name of the client to send the message to.
     * \param trick_count is an int which represents the trick value the client selected.
     * \param trump_suit is a QString which represents the chosen trump suit.
     */
    bool sendContract( QString client_name, int trick_count, QString trump_suit);

    /*!
     * \brief Sends a won update message to the relevant client.
     * \param client_to is a QString indicating which client to send the message to.
     * \param team is a QString indicating which team won.
     * \param note is a QString cotaining an additional information as per the communication protocol.
     */
    bool sendWonUpdate( QString client_to, QString team, QString player, QString note);

    /*!
     * \brief Sends the dummy ID message to the relevant client.
     * \param QString client_name is the client to which the message must be sent.
     * \param QString dummy_name is the name of the dummy as identified by the dummy client.
     */
    bool sendDummyID( int, QString client_name, QString dummy_name);

    /*!
     * \brief Sends an array of cards to the relevant client. Can be used to send them their hand (for example).
     * \param user_name is a QString indicating which client the message should be sent to.
     * \param cards is a QString containing a comma deliminated list of cards to send.
     * \param note is a QString containing any additional information as per the communication protocol.
     */
    bool sendCardArray( int, QString user_name, QString cards, QString note);

    /*!
     * \brief Sends a score update message to the relevant client.
     * \param QString user_name is the name of the client who must receive the message.
     * \param QString wabove is the "we above" value.
     * \param QString wbelow is the "we below" value.
     * \param QString tabove is the "they above" value.
     * \param QString tbelow is the "they below" value.
     */
    bool scoreUpdate( QString user_name, QString wabove, QString wbelow, QString tabove, QString tbelow);

    /*!
     * \brief Wrties a message to every client connected to the server.
     * \param json is a QJsonObject which cotains the json encoded message to send to every client.
     */
    void multicastMsg(QJsonObject json);

    /*!
     * \brief Returns the IPv4 address of the server which is not the address of localhost.
     */
    QString getIP();

    /*!
     * \brief Sends a game status message to the client specified by user_name.
     * \brief user_name is a QString which indicates to which client the message should be sent.
     * \brief list is a QStringList which indicates to which contains trick number, deal number and game number.
     */
    bool sendGameStatus( QString user_name, QStringList list);

protected:
    /*!
     * \brief Handles all incomming connections by assigning the client to a thread, connecting the relevant signals and slots and finally appending that thread to the client list.
     * \param socketDescriptor is a qintptr which represents the socket descriptor of the incomming client.
     */
    void incomingConnection(qintptr socketDescriptor);

private:
    /*!
     * \brief Sends an encrypted, JSON-encoded string to the client specified by *client.
     * \param json is QJsonObject which contains all the information the calling function intends to send to the client.
     * \param client is a ClientThread which indicates to which client the calling function intends to send the message.
     */
    void writeJSON(QJsonObject json, ClientThread *client);

    /*!
     * \brief Returns a pointer to a clientHandle based on the socket descriptor's ID.
     * \param _id is the socket desciptor's ID to search for.
     */
    ClientHandle *getClient(int _id) const;

    /*!
     * \brief Returns a pointer to a clientHandle based on the client's name.
     * \param _name is a QString which will be used to search the client list.
     */
    ClientHandle *getClientByName(const QString &_name) const;

    /*!
     * \brief Returns a pointer to a clientThread based on the client's name.
     * \param _name is a QString which will be used to search the client list.
     */
    ClientThread *getClientThreadByName(const QString &_name) const;

    /*!
     * \brief Returns a pointer to a ClientHandle based on the client's direction.
     * \param _name is a QString which will be used to search the client list.
     */
    //ClientHandle *getClientByDirection(int dir) const;

    /*!
     * \brief Returns a QList of every ClientHandle the server knows about.
     */
    QList<ClientHandle*> getClients() const;

    QList<ClientThread*> clientList;

    QStringList clientNames;

    GameMaster *gm;

    int num_clients;

    QStringList client_requested;

    Card *card;

    bool plaintext;

    /*!
     * \brief These member variables are used to determine the registration server.
     */
    QUdpSocket *udpsocket;
    QHostAddress regServerAddress;
    QTcpSocket *regServerSocket;

    /*!
     * \brief The following boolean attributes are used together with the functionFlag to determine what the received message was.
     */
    QString functionFlag;
    bool ack_bidupdate;
    bool ack_phase;
    bool ack_contract;
    bool ack_sendcards;
    bool ack_dummyid;
    bool ack_sendstatus;
    bool ack_sendmove;
    bool ack_wonupdate;
    bool ack_scoreupdate;

    SimpleCrypt *crypto;

private slots:
    /*!
     * \brief dataReceived is triggered when the UDP socket has emitted a readyRead signal.
     */
    void dataReceived();

    /*!
     * \brief regServerConnected is triggered when a connection is made to the registration server.
     */
    void regServerConnected();

    /*!
     * \brief regServerRead reads any message from the registration server for debugging.
     */
    void regServerRead();

    /*!
     * \brief When the server receives a message from a client, this function is called. Its job is to parse the message and determine what action to take.
     * \param msg is a QString which contains the encrypted JSON-encoded string which was received from the client.
     */
    void processMsg(const QByteArray &msg);

    /*!
     * \brief This function is called whenever a client leaves the server. It removes the client from the client list and alerts the other clients.
     * \param threadID is an int which indicates which client has disconnected from the server.
     */
    void threadFinished(int threadId);
};

#endif // SERVER_H
